package com.lcf.user.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <dependency>
 * <groupId>org.apache.httpcomponents</groupId>
 * <artifactId>httpmime</artifactId>
 * <version>4.5.3</version>
 * </dependency>
 * <dependency>
 *     <groupId>org.apache.httpcomponents</groupId>
 *     <artifactId>httpclient</artifactId>
 *     <version>4.5.3</version>
 * </dependency>
 *
 * <dependency>
 *     <groupId>org.apache.httpcomponents</groupId>
 *     <artifactId>httpcore</artifactId>
 *     <version>4.4.8</version>
 * </dependency>
 */
@Slf4j
public class HttpUtil {
    private static PoolingHttpClientConnectionManager connMgr;
    private static RequestConfig requestConfig;
    private final static int MAX_TIMEOUT = 7000;

    static {
        // 设置连接池
        connMgr = new PoolingHttpClientConnectionManager();
        // 设置连接池大小
        connMgr.setMaxTotal(100);
        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
        connMgr.setValidateAfterInactivity(1000);
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(MAX_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
        requestConfig = configBuilder.build();
    }


    public static String doGet(String url) {
        return doGet(url, null, null);
    }

    public static String doGet(String url, Map<String, String> params) {
        return doGet(url, params, null);
    }

    public static String doGet(String url, Map<String, String> params, Map<String, String> headers) {
        //1.创建http客户端对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = "";
        try {
            //2.构建一个URI对象,根据url及参数
            URIBuilder uriBuilder = new URIBuilder(url);
            //2.1请求参数
            if (params != null && params.size() > 0) {
                for (String key : params.keySet()) {
                    uriBuilder.addParameter(key, params.get(key));
                }
            }
            URI uri = uriBuilder.build();
            //3.创建一个get请求
            HttpGet httpGet = new HttpGet(uri);
            //3.1请求头
            if (headers != null && headers.size() > 0) {
                for (String key : headers.keySet()) {
                    httpGet.addHeader(key, headers.get(key));
                }
            }
            //4.执行get请求,得到响应
            response = httpClient.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == HttpStatus.OK.value()) {
                //5.从响应对象中获取响应数据
                result = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (URISyntaxException e) {
            log.error("", e);
            log.error("", e);
        } catch (ClientProtocolException e) {
            log.error("", e);
        } catch (IOException e) {
            log.error("", e);
        } finally {
            HttpClientUtils.closeQuietly(response);
            HttpClientUtils.closeQuietly(httpClient);
        }

        return result;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }

    public static String doPost(String url, Map<String, String> params) {
        String result = "";
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        //封装post请求参数
        int size = params.size();
        if (params != null && size > 0) {
            List<NameValuePair> pairList = new ArrayList<>(size);
            for (String key : params.keySet()) {
                pairList.add(new BasicNameValuePair(key, params.get(key)));
            }
            try {
                UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(pairList, "UTF-8");

                httpPost.setHeader("Content-Type", "application/json");
                httpPost.setEntity(formEntity);
                //执行post请求
                CloseableHttpResponse response = null;
                try {
                    response = httpClient.execute(httpPost);
                    int statusCode = response.getStatusLine().getStatusCode();
                    if (statusCode != HttpStatus.OK.value()) {
                        return null;
                    }
                    HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        result = EntityUtils.toString(entity, "UTF-8");
                    }
                } catch (IOException e) {
                    log.error("", e);
                } finally {
                    HttpClientUtils.closeQuietly(response);
                }
            } catch (UnsupportedEncodingException e) {
                log.error("", e);
            }
        }
        HttpClientUtils.closeQuietly(httpClient);

        return result;
    }

    /**
     * 发送 POST 请求（HTTP），带字符串
     *    
     */
    public static String doPostWithStr(String url, String str) {

        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = null;
        HttpPost httpPost = new HttpPost(url);
        try {
            httpPost.setConfig(requestConfig);
            httpPost.setEntity(new StringEntity(str, Charset.forName("UTF-8")));
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.OK.value()) {
                return null;
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "UTF-8");
            }

        } catch (IOException e) {
            log.error("发送 POST请求失败，原因：{}", e.getMessage());
        } finally {
            HttpClientUtils.closeQuietly(response);
            HttpClientUtils.closeQuietly(httpClient);
        }
        return result;
    }

    /**
     * 发送 POST 请求（HTTP），JSON形式 
     */
    public static String doPostWithJson(String url, Object json) {

        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = null;
        HttpPost httpPost = new HttpPost(url);

        try {

            httpPost.setConfig(requestConfig);

            StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");// 解决中文乱码问题
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");

            httpPost.setEntity(stringEntity);
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.OK.value()) {
                return null;
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "UTF-8");
            }
        } catch (IOException e) {
            log.error("", e);
        } finally {
            HttpClientUtils.closeQuietly(response);
            HttpClientUtils.closeQuietly(httpClient);
        }
        return result;
    }


    /**
     *     * 发送 SSL POST 请求（HTTPS），K-V形式
     *    
     */
    public static String doPostSSL(String url, Map<String, String> params) {

        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(createSSLConnSocketFactory())
                .setConnectionManager(connMgr)
                .setDefaultRequestConfig(requestConfig)
                .build();

        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        String result = null;

        try {

            httpPost.setConfig(requestConfig);

            List pairList = new ArrayList(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
                pairList.add(pair);
            }

            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.OK.value()) {

                return null;

            }

            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "UTF-8");
            }
        } catch (Exception e) {
            log.error("", e);
        } finally {
            HttpClientUtils.closeQuietly(response);
            HttpClientUtils.closeQuietly(httpClient);
        }
        return result;
    }

    /**
     *     * 发送 SSL POST 请求（HTTPS），JSON形式
     *    
     */
    public static String doPostSSL(String url, Object json) {

        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(createSSLConnSocketFactory())
                .setConnectionManager(connMgr)
                .setDefaultRequestConfig(requestConfig).build();

        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        String result = null;
        try {
            httpPost.setConfig(requestConfig);

            StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");// 解决中文乱码问题
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");

            httpPost.setEntity(stringEntity);
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.OK.value()) {
                return null;
            }

            HttpEntity entity = response.getEntity();

            if (entity != null) {
                result = EntityUtils.toString(entity, "UTF-8");
            }

        } catch (Exception e) {
            log.error("", e);
        } finally {
            HttpClientUtils.closeQuietly(response);
            HttpClientUtils.closeQuietly(httpClient);
        }
        return result;
    }

    /**
     * 创建SSL安全连接
     *    
     */
    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {

        SSLConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();

        return sslsf;

    }

    /**
     *   模拟表单上传文件
     */
    public static JSONObject postWithFile(File postFile, String postUrl, Map<String, String> postParam) throws Exception {

        JSONObject res = new JSONObject();
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {

            //把一个普通参数和文件上传给下面这个地址    是一个servlet
            HttpPost httpPost = new HttpPost(postUrl);

            //把文件转换成流对象FileBody
            FileBody fundFileBin = new FileBody(postFile);
            //设置传输参数
            MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();
            multipartEntity.addPart(postFile.getName(), fundFileBin);//相当于

            if (!CollectionUtils.isEmpty(postParam)) {

                //设计文件以外的参数
                Set<String> keySet = postParam.keySet();
                for (String key : keySet) {
                    //相当于
                    multipartEntity.addPart(key,
                            new StringBody(postParam.get(key),
                                    ContentType.create("text/plain", "UTF-8")));

                }
            }

            HttpEntity reqEntity = multipartEntity.build();
            httpPost.setEntity(reqEntity);
            log.info("发起请求的页面地址 " + httpPost.getRequestLine());
            //发起请求  并返回请求的响应
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {

                //打印响应状态
                log.info(response.getStatusLine().toString());
                res.put("statusCode", response.getStatusLine().getStatusCode());
                //获取响应对象
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {

                    //打印响应长度
                    log.info("Response content length: " + resEntity.getContentLength());

                    //打印响应内容
                    res.put("data", EntityUtils.toString(resEntity, Charset.forName("UTF-8")));
                }

                //销毁
                EntityUtils.consume(resEntity);
            } catch (Exception e) {
                log.error("", e);
            } finally {
                HttpClientUtils.closeQuietly(response);
            }
        } catch (ClientProtocolException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } finally {
            HttpClientUtils.closeQuietly(httpClient);
        }
        log.info("uploadFileByHTTP result:" + res);
        return res;
    }

    /**
     *     * 原生字符串发送put请求
     **/
    public static String doPut(String url, String token, String jsonStr) {

        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPut httpPut = new HttpPut(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(35000)
                .setConnectionRequestTimeout(35000)
                .setSocketTimeout(60000)
                .build();

        httpPut.setConfig(requestConfig);

        httpPut.setHeader("Content-type", "application/json");
        httpPut.setHeader("DataEncoding", "UTF-8");
        httpPut.setHeader("access-token", token);
        CloseableHttpResponse httpResponse = null;

        try {

            httpPut.setEntity(new StringEntity(jsonStr));
            httpResponse = httpClient.execute(httpPut);
            HttpEntity entity = httpResponse.getEntity();
            String result = EntityUtils.toString(entity);
            return result;
        } catch (ClientProtocolException e) {
            log.error("", e);

        } catch (IOException e) {
            log.error("", e);

        } finally {
            HttpClientUtils.closeQuietly(httpResponse);
            HttpClientUtils.closeQuietly(httpClient);
        }

        return null;

    }

    /**
     *     * 发送delete请求
     **/
    public static String doDelete(String url, String token, String jsonStr) {

        CloseableHttpClient httpClient = HttpClients.createDefault();

        HttpDelete httpDelete = new HttpDelete(url);

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(35000)
                .setConnectionRequestTimeout(35000)
                .setSocketTimeout(60000)
                .build();
        httpDelete.setConfig(requestConfig);

        httpDelete.setHeader("Content-type", "application/json");
        httpDelete.setHeader("DataEncoding", "UTF-8");
        httpDelete.setHeader("access-token", token);
        CloseableHttpResponse httpResponse = null;

        try {

            httpResponse = httpClient.execute(httpDelete);
            HttpEntity entity = httpResponse.getEntity();
            String result = EntityUtils.toString(entity);
            return result;

        } catch (ClientProtocolException e) {
            log.error("", e);

        } catch (IOException e) {
            log.error("", e);

        } finally {
            HttpClientUtils.closeQuietly(httpResponse);
            HttpClientUtils.closeQuietly(httpClient);
        }
        return null;
    }

    /**
     * 发送微信postWechatWithFile请求
     **/

    public static JSONObject postWechatWithFile(File postFile, String postUrl, Map<String, String> postParam) throws Exception {

        JSONObject res = new JSONObject();
        CloseableHttpClient httpClient = HttpClients.createDefault();

        try {

            //把一个普通参数和文件上传给下面这个地址    是一个servlet
            HttpPost httpPost = new HttpPost(postUrl);

            //把文件转换成流对象FileBody
            FileBody fundFileBin = new FileBody(postFile);

            //设置传输参数
            MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();

            multipartEntity.addPart(postFile.getName(), fundFileBin);//相当于
            multipartEntity.addBinaryBody("media", postFile, ContentType.MULTIPART_FORM_DATA, postFile.getPath());

            if (!CollectionUtils.isEmpty(postParam)) {

                //设计文件以外的参数
                Set<String> keySet = postParam.keySet();

                for (String key : keySet) {
                    //相当于
                    multipartEntity.addPart(key,
                            new StringBody(postParam.get(key),
                                    ContentType.create("text/plain", "UTF-8")));
                }

            }

            HttpEntity reqEntity = multipartEntity.build();
            httpPost.setEntity(reqEntity);
            log.info("发起请求的页面地址 " + httpPost.getRequestLine());

            //发起请求  并返回请求的响应
            CloseableHttpResponse response = httpClient.execute(httpPost);

            try {
                //打印响应状态
                log.info(response.getStatusLine().toString());
                res.put("statusCode", response.getStatusLine().getStatusCode());
                //获取响应对象
                HttpEntity resEntity = response.getEntity();

                if (resEntity != null) {
                    //打印响应长度
                    log.info("Response content length: " + resEntity.getContentLength());
                    //打印响应内容
                    res.put("data", EntityUtils.toString(resEntity, Charset.forName("UTF-8")));
                }

                //销毁
                EntityUtils.consume(resEntity);
            } catch (Exception e) {
                log.error("", e);
            } finally {
                HttpClientUtils.closeQuietly(response);
            }
        } catch (ClientProtocolException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } finally {
            HttpClientUtils.closeQuietly(httpClient);
        }
        log.info("uploadFileByHTTP result:" + res);
        return res;
    }
}
